import { FreezeRender } from './freeze-render';
import { Config } from './config';
import { Inject } from '../decorators/inject';
import { NExcel } from '../types';
import { Injectable } from '../decorators/inject';
import { Hook } from './hook';
import { NBorder } from '../types/style.interface';


@Injectable('BorderRender')
export class BorderRender {
    protected ctx: CanvasRenderingContext2D;
    protected freezeInfo = {
        width: 0,
        height: 0,
        startX: 0,
        startY: 0
    }
    constructor(
        protected conf: Config,
        @Inject(NExcel.TableDataCanvasToken) protected canvasDataEle: HTMLCanvasElement,
        protected hook: Hook,
        protected freezeRender: FreezeRender
    ) {

    }
    public init() {
        this.ctx = this.canvasDataEle.getContext('2d');
        this.hook.beforeDataRender.add(() => {
            let w = this.freezeRender.getStartColWidth();
            let h = this.freezeRender.getStartRowHeight();
            this.freezeInfo = {
                width: w,
                height: h,
                startX: this.conf.header.row.width + w,
                startY: this.conf.header.col.height + h
            }
        });
    }
    protected lineBorder(start: TCoord, end: TCoord, border: NBorder.IBorderStyle) {
        this.ctx.save();
        this.ctx.beginPath();
        this.ctx.moveTo(start.x, start.y);
        this.ctx.lineWidth = border.width + 0.5;
        this.ctx.strokeStyle = border.color;
        this.ctx.lineTo(end.x, end.y);
        if (border.type == NBorder.EBorderType.dash) {
            this.ctx.setLineDash([6, 3]);
        }
        this.ctx.stroke();
        this.ctx.restore();
    }
    protected borderBoundaryRect(row: number, col: number, rowspan: number, colspan: number, _start: TCoord, _end: TCoord) {
        let start = {..._start};
        let end = {..._end};
        if(this.conf.freeze.row !== -1) {
            if(row > this.conf.freeze.row) {
                if(start.y < this.freezeInfo.startY) {
                    start.y = this.freezeInfo.startY;
                }
            } else {
                if(start.y < this.conf.header.col.height + 1) {
                    start.x = this.conf.header.col.height + 1;
                }
            }
            if(row + rowspan - 1 <= this.conf.freeze.row) {
                if(end.y > this.freezeInfo.startY) {
                    end.x = this.freezeInfo.startY - 1;
                }
            }
        } else {
            if(start.y < this.conf.header.col.height + 1) {
                start.y = this.conf.header.col.height + 1;
            }
        }

        if(this.conf.freeze.col !== -1) {
            if(col > this.conf.freeze.col) {
                if(start.x < this.freezeInfo.startX) {
                    start.x = this.freezeInfo.startX;
                }
            } else {
                if(start.x < this.conf.header.row.width + 1) {
                    start.x = this.conf.header.row.width + 1
                }
            }
            if(col + colspan - 1 <= this.conf.freeze.col) {
                if(end.x > this.freezeInfo.startX) {
                    end.x = this.freezeInfo.startX - 1;
                }
            }
        } else {
            if(start.x < this.conf.header.row.width + 1) {
                start.x = this.conf.header.row.width + 1;
            }
        }
        return {start, end};
    }
    protected drawTop(position: TRange, _start: TCoord, size: TSize, border: NBorder.IBorderStyle) {
        let start = {..._start};
        let end = {x: start.x + size.w, y: start.y};
        let {start: newStart, end: newEnd} = this.borderBoundaryRect(position.row, position.col, position.rowspan, position.colspan, start, end);
        if(start.y < newStart.y) {
            return;
        }
        if(end.x < newStart.x) {
            return;
        }
        if(start.x < newStart.x) {
            start.x = newStart.x;
        }
        if(end.x > newEnd.x) {
            end.x = newEnd.x;
        }
        
        this.lineBorder(start, end, border);
    }
    protected drawBottom(position: TRange,  _start: TCoord, size: TSize, border: NBorder.IBorderStyle) {
        let start = {..._start};
        let end = {x: start.x + size.w, y: start.y};
        let {start: newStart, end: newEnd} = this.borderBoundaryRect(position.row, position.col, position.rowspan, position.colspan, start, end);
        if(start.y < newStart.y) {
            return;
        }
        if(end.x < newStart.x) {
            return;
        }
        if(start.x < newStart.x) {
            start.x = newStart.x;
        }
        if(end.x > newEnd.x) {
            end.x = newEnd.x;
        }
        this.lineBorder(start, end, border);
    }
    protected drawLeft(position: TRange,  _start: TCoord, size: TSize, border: NBorder.IBorderStyle) {
        let start = {..._start};
        let end = {x: start.x, y: start.y + size.h};
        let {start: newStart, end: newEnd} = this.borderBoundaryRect(position.row, position.col, position.rowspan, position.colspan, start, end);
        if(start.x < newStart.x) {
            return;
        }
        if(end.y < newStart.y) {
            return;
        }
        if(start.y < newStart.y) {
            start.y = newStart.y;
        }
        if(end.y > newEnd.y) {
            end.y = newEnd.y;
        }
        this.lineBorder(start, end, border);
    }
    protected drawRight(position: TRange, _start: TCoord, size: TSize, border: NBorder.IBorderStyle) {
        let start = {..._start};
        let end = {x: start.x, y: start.y + size.h};
        let {start: newStart, end: newEnd} = this.borderBoundaryRect(position.row, position.col, position.rowspan, position.colspan, start, end);
        if(start.x < newStart.x) {
            return;
        }
        if(end.y < newStart.y) {
            return;
        }
        if(start.y < newStart.y) {
            start.y = newStart.y;
        }
        if(end.y > newEnd.y) {
            end.y = newEnd.y;
        }
        this.lineBorder(start, end, border);
    }
    public drawBorder(position: TRange, start: TCoord, size: TSize, borders: Partial<NBorder.IBorder>) {
        if (borders.top != null && borders.top != undefined) {
            this.drawTop(position, start, size, borders.top);
        }
        if (borders.right != null && borders.right != undefined) {
            let origin = { x: start.x + size.w - 1, y: start.y};
            this.drawRight(position, origin, size, borders.right)
        }
        if (borders.bottom != null && borders.bottom != undefined) {
            let origin = { x: start.x - 1, y: start.y + size.h - 1};
            this.drawTop(position, origin, size, borders.bottom);
        }
        if (borders.left != null && borders.left != undefined) {
            let origin = { x: start.x, y: start.y};
            this.drawLeft(position, origin, size, borders.left);
        }
    }
}